/*
 * This file is part of Advanced ABX
 *
 * Copyright 2010 Christian Uebber
 *
 * Advanced ABX is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2, as
 * published by the Free Software Foundation.
 *
 * Advanced ABX is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Advanced ABX.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * OutInFader.java
 *
 *  This file is part of the NilPop package.
 */
package audio;

import javax.sound.sampled.AudioFormat;

public class OutInFader {
    
	private static float ditherBits = 0.3f;
    private static TypeOfFade type = TypeOfFade.PARABOLIC;

    private OutInFader () {
    	
    }
    
    public static void process(boolean fadeIn, boolean fadeOut, byte[] active, int srcOffset, byte[] result, int dstOffset,
                        int transitionLenght, AudioFormat format) {
    	
    	int frameLenght = active.length/format.getFrameSize();
    	
        // Create arrays of float arrays (one for each channel) to hold samples
        float[][] floatBuffer = new float[format.getChannels()][frameLenght];
        // Read byte arrays into float arrays
        FloatSampleTools.byte2float(active, srcOffset, floatBuffer, 0, frameLenght, format);

        // Special treatment for uneven numbers of samples
        int overlap = transitionLenght % 2 == 0 ? 0 : 1;
        int len = transitionLenght + overlap;
        
        // Fade out last buffer
        if (fadeOut == true) {
	        for (float[] f : floatBuffer) {
	            for (int i = 0; i < len; i++) {
	                f[f.length-len+i] = fadeOut(f[f.length-len+i], i, len - 1);
	            }
	        }
        }
     // Fade in next buffer
        if (fadeIn == true) { 
            for (float[] f : floatBuffer) {
                for (int i = 0; i < len; i++) {
                    f[i - overlap] = fadeIn(f[i - overlap], i, len - 1);
                }
            }
        }
        // Write fade into floatBuffer to destination
        FloatSampleTools.float2byte(floatBuffer, 0, result, dstOffset, frameLenght, format, ditherBits);
    }

    private static float fadeIn(float sample, int index, int range) {
        switch (type) {
            case TRIANGULAR:
                return sample * index / range;
            case PARABOLIC:
                float f = (float) index / range;
                return sample * f * f;
        }
        return -1000;
    }

    private static float fadeOut(float sample, int index, int range) {
        switch (type) {
            case TRIANGULAR:
                return sample * ((float) index / range * -1f + 1);
            case PARABOLIC:
                float f = 1 - ((float) index / range);
                return sample * f * f;
        }
        return -1000;
    }


    public static TypeOfFade getTypeOfFade(TypeOfFade type) {
        return type;
    }


    public static void setTypeOfFade(TypeOfFade fadeType) {
        type = fadeType;
    }

    public float getDitherBits() {
        return ditherBits;
    }

    public static void setDitherBits(float dither) {
       ditherBits = dither;
    }

    public enum TypeOfFade {
        TRIANGULAR, PARABOLIC
    }
}
